/*
 * AnimationPathMgr.cpp
 *
 *  Created on: Apr 21, 2013
 *      Author: pk
 */

#include "Source.h"
#include "AnimationPathMgr.h"
#include "AnimationPathMgr.moc"
#include <QAction>
#include <QtAlgorithms>


static Point2D invalid_point = Point2D(-99999,-99999);
AnimationPathMgr *AnimationPathMgr::_instance = 0;

AnimationPathMgr::AnimationPathMgr() :
    _selectedSource(NULL),
    _recordPointTimer(),
    is_recording(false),
    lastRecordedPoint(invalid_point),
    sourceSelectedForEdit(NULL)
{
    QObject::connect(&_recordPointTimer, SIGNAL(timeout()), this, SLOT(recordPoints()));
}

AnimationPathMgr::~AnimationPathMgr()
{
}


AnimationPathMgr *AnimationPathMgr::getInstance() {

    if (_instance == 0) {
        _instance = new AnimationPathMgr;
        Q_CHECK_PTR(_instance);
    }

    return _instance;
}

void AnimationPathMgr::deleteInstance() {
    if (_instance != 0)
        delete _instance;
}

void AnimationPathMgr::startRecording()
{
    QAction* action = static_cast<QAction*>(sender());
    if(action->text() == "Start Recording Path")
    {
        if(recordedPaths.find(_selectedSource) != recordedPaths.end())
        {
            recordedPaths.remove(_selectedSource);
        }
        recordedPaths.insert(_selectedSource, QList<Point2D>());
        sourcePathColor.insert(_selectedSource, QColor::fromHsv ( rand()%180 + 179, 250, 250));
        is_recording = true;
        _recordPointTimer.setInterval(10);
        _recordPointTimer.start();
        action->setText("Stop Recording");
    }
    else
    {
        stopRecording();
        action->setText("Start Recording Path");
    }
    // Start timer for collecting point after every 2 ms?
}

void AnimationPathMgr::startReplayPath()
{
   QTimer *replayTimer = new QTimer();
   replayTimer->setInterval(500);
   ReplayData data(_selectedSource);
   replayTimers.insert(replayTimer, data);
   QObject::connect(replayTimer, SIGNAL(timeout()), this, SLOT(replayPoints()));
   replayTimer->start();
}

void AnimationPathMgr::stopReplayPath()
{
   QAction *act = static_cast<QAction*>(sender());
   QVariant v = act->data();
   QTimer* timer = (QTimer *) v.value<void *>();
   timer->stop();
   replayTimers.remove(timer);
   delete timer;
}

void AnimationPathMgr::editRecordedPath()
{
    QAction *act = static_cast<QAction*>(sender());
    QVariant v = act->data();
    sourceSelectedForEdit = (Source *) v.value<void *>();
}

void AnimationPathMgr::stopRecording()
{
    is_recording = false;
    _recordPointTimer.stop();
    lastRecordedPoint = invalid_point;
    QMap< Source*, QList<Point2D> >::iterator itr = recordedPaths.find(_selectedSource);
    QList<Point2D> newList;
    if(itr.value().size() > 0)
    {
        Point2D prev_pnt = itr.value().at(0);
        newList.append(prev_pnt);
        foreach (Point2D pnt, itr.value())
        {
            if(calcDistance(prev_pnt, pnt) > 20)
            {
                prev_pnt = pnt;
                newList.append(prev_pnt);
            }
        }
        newList.append(itr.value().at(itr.value().size() - 1));
    }
    itr.value() = newList;
}

void AnimationPathMgr::recordPoints()
{
    QMap< Source*, QList<Point2D> >::iterator itr = recordedPaths.find(_selectedSource);
    if(itr != recordedPaths.end())
    {
        Point2D currentPoint(_selectedSource->getAlphaX(), _selectedSource->getAlphaY());
        if(currentPoint.X != lastRecordedPoint.X || currentPoint.Y != lastRecordedPoint.Y)
        {
            itr.value().append(currentPoint);
            lastRecordedPoint = currentPoint;
        }
    }
    else
    {
        Q_ASSERT(0);
    }
}

void AnimationPathMgr::replayPoints()
{
   QTimer* send = static_cast<QTimer*>(sender());
   ReplayData data = replayTimers.find(send).value();
   QList<Point2D> points = recordedPaths.find(data.source).value();

   if(data.go_reverse)
   {
      data.last_index = data.last_index - 1;
      if(data.last_index <= 0)
      {
         data.go_reverse = false;
      }
   }
   else
   {
      data.last_index = data.last_index + 1;
      if(data.last_index >= points.size())
      {
         data.go_reverse = true;
      }
   }

   replayTimers.insert(send, data);


   if(data.last_index >= 0 && data.last_index < points.size())
      data.source->setAlphaCoordinates(points[data.last_index].X, points[data.last_index].Y);

}

double AnimationPathMgr::calcDistance(Point2D prev, Point2D next) const
{
    double x = next.X - prev.X;
    double y = next.Y - prev.Y;
    return qSqrt(x*x + y*y);
}

void AnimationPathMgr::drawPaths()
{
    for(QMap< Source*, QList<Point2D> >::iterator itr = recordedPaths.begin(); itr != recordedPaths.end(); ++itr)
    {
       QColor color = sourcePathColor.find(itr.key()).value();
        // Draw Path for all recorded paths
       if(is_recording && itr.key() == _selectedSource)
       {
          glColor4f(color.redF(), color.greenF(), color.blueF(), 1);
       }
       else
       {
          glColor4f(color.redF(), color.greenF(), color.blueF(), .4);
       }
        glBegin(GL_LINE_STRIP);
        glLineWidth(25.0);
        foreach (Point2D pnt, itr.value())
        {
            glVertex2f(pnt.X, pnt.Y);
        }

        glEnd();

        if(sourceSelectedForEdit == itr.key())
        {
            glPointSize(8);

            glBegin(GL_POINTS);

            if(itr.value().size() > 0)
            {
                foreach (Point2D pnt, itr.value())
                {
                     glVertex2f(pnt.X, pnt.Y);
                }
            }

            glEnd();
        }

    }

}

bool AnimationPathMgr::hasCurrentSourceRecordedPath() const
{
    return !is_recording && recordedPaths.find(_selectedSource) != recordedPaths.constEnd();
}

bool AnimationPathMgr::handlePathClick() const
{
    return true;
}

void AnimationPathMgr::setSelectedSource(Source *selectedSource)
{
    _selectedSource = selectedSource;
}



